﻿using System.Collections;
using System.Collections.Generic;
using UnityEngine;
/// <summary>
/// TODO 
/// （完成）this.Append()   调整头发长度
/// （完成）Mirror Apply    镜像修改模型
/// （完成）头发选择反馈，编辑中禁用选择防止误选。
/// （完成）简单物理
/// 操作斜率的UI
/// </summary>
public partial class HairGen
{
    [ShowButton("删除头发（X）")]
    void DeleteHair()
    {
        var h = hairCurr;
        if (h == null) return;
        if (h.curveData.pair != null)
        {
            if (h.curveData.pair.name.EndWithIC(".l") ||
                h.curveData.pair.name.EndWithIC(".r"))
            {
                h.curveData.pair.name = StringTool.CutRight(h.curveData.pair.name, 2);
            }
        }
        DeleteHair(h);
        Selector.current = null;
    }
    [ShowButton("为头发添加镜像（M）")]
    void AddMirrorHair()
    {
        if (hairCurr.curveData.pair != null) return;
        ApplyMirrorHair(null);
        OnClickHair();
    }
    void ApplyMirrorHair(Hair mir)
    {
        var h = hairCurr;
        if (h != null)
        {
            if (mir == null)
            {
                var goMir = h.Copy();

                h.gameObject.name += ".l";
                goMir.gameObject.name += ".r";

                hairs.Add(goMir);
                h.curveData.pair = goMir;
            }
            else
            {
                var goMir = h.Copy();
                goMir.name = mir.name;
                hairs.Add(goMir.GetComponent<Hair>());

                DeleteHair(mir);
            }
            mir.curveData.circleAngle = 360 - h.curveData.circleAngle;
        }
    }
    [ShowButton("应用面板的数据（Enter）")]
    public void ApplyGenData_Curr()
    {
        if (hairCurr == null) return;
        ApplyGenData(hairCurr);
        OnClickHair();
    }
    public Hair ResetGenData(Hair hair)
    {
        GenData gd = hair.genData;
        Curve3 curve = hair.curveData.curve;
        var hName = hair.name;
        var pair = hair.curveData.pair;
        var relas = hair.curveData.relaHairs;
        var angle = hair.curveData.circleAngle;

        DeleteHair(hair);

        Transform rig; Hair h;
        Selector.current = NewRigGO(hName, out h, out rig).transform;
        hairs.Add(h);
        //h.genData = GetDataFromInspector(h, length, false);
        h.genData = gd;
        h.curveData = new CurveData(h);
        h.curveData.curve = curve;
        GenMeshTool.GenHair(h, hairMat, rig);

        if (pair != null) ApplyMirrorHair(pair);

        h.curveData.circleAngle = angle;
        if (relas.NotEmpty())
        {
            Debug.Log("Apply and GenCircle");
            h.curveData.relaHairs = relas;
            GenerateCircle();
        }

        /// Snap (With Mirror)
        h.curveData.SnapBonesToCurve();

        return h;
    }
    public Hair ApplyGenData(Hair hair)
    {
        GenData gd = hair.genData;
        Curve3 curve = hair.curveData.curve;
        var hName = hair.name;
        var pair = hair.curveData.pair;
        var relas = hair.curveData.relaHairs;
        var euler = hair.curveData.pivotEuler;
        var scale = hair.curveData.circleScale;
        var angle = hair.curveData.circleAngle;

        DeleteHair(hair);

        Transform rig; Hair h;
        Selector.current = NewRigGO(hName, out h, out rig).transform;
        hairs.Add(h);
        h.genData = GetDataFromInspector(h, length, false);

        h.curveData = new CurveData(h);
        h.curveData.curve = curve;
        GenMeshTool.GenHair(h, hairMat, rig);

        h.curveData.circleAngle = angle;
        if (pair != null) ApplyMirrorHair(pair);

        if (relas.NotEmpty())
        {
            Debug.Log("Apply and GenCircle");
            h.curveData.relaHairs = relas;
            h.curveData.pivotEuler = euler;
            h.curveData.circleScale = scale;
            GenerateCircle();
        }
        /// Snap (With Mirror)
        h.curveData.SnapBonesToCurve();
        return h;
    }
    void DeleteHair(IList<Hair> hairs)
    {
        foreach (var hair in hairs)
        {
            DeleteHair(hair);
        }
    }
    void DeleteHair(Hair hair)
    {
        hairs.Remove(hair);

        var t = hair.transform;
        t.ClearChildren();
        t.parent = null;
        Destroy(t.gameObject);
    }
    int curveEdit_idx;
    [ShowButtonRow("宽度曲线（Q）", "厚度曲线（W）", "前半形状曲线（E）")]
    void CurveEdit(int idx)
    {
        curveEdit_idx = idx;
        if (idx == 0)
        {
            UICurve.I.mirror = false;
            UICurve.I.Curve = curveWidth;
        }
        else if (idx == 1)
        {
            UICurve.I.mirror = false;
            UICurve.I.Curve = curveThickness;
        }
        else if (idx == 2)
        {
            UICurve.I.mirror = true;
            UICurve.I.Curve = curveCrsSecFront.Before(0.5f);
        }
    }
    void Append()
    {
        float length;
        if (!GetMousePos(out length)) return;
        length *= lengthProjFactor;


        var hSel = hairCurr;
        GenData gd = hSel.genData;
        Curve3 curve = hSel.curveData.curve;
        var hName = hSel.name;
        var pair = hSel.curveData.pair;
        var relas = hSel.curveData.relaHairs;

        DeleteHair(hSel);

        Transform rig; Hair h;
        Selector.current = NewRigGO(hName, out h, out rig).transform;
        hairs.Add(h);
        h.genData = GetDataFromInspector(h, gd.length + length, false);

        h.curveData = new CurveData(h);
        h.curveData.curve = curve;
        GenMeshTool.GenHair(h, hairMat, rig);


        //curve
        Vector3[] ps = new Vector3[3];
        ps[0] = posList[Mathf.RoundToInt((posList.Count - 1) * 0.33333f)];
        ps[1] = posList[Mathf.RoundToInt((posList.Count - 1) * 0.66667f)];
        ps[2] = posList[posList.Count - 1];

        var cd = hairCurr.curveData;
        cd.curve.Last().outMode = KeyMode.Bezier;
        cd.curve.Last().outTangent = ps[0];
        cd.curve.Add(new Key3(ps[2], ps[1]));

        //mirror
        if (pair != null) ApplyMirrorHair(pair);

        cd.SnapBonesToCurve();

        TwistToFaceCam(cd.bones.LastM1(), cd.curve.LastM1());
        TwistToFaceCam(cd.bones.Last(), cd.curve.Last());

        cd.SnapBonesToCurve();
        append = false;

        if (relas.NotEmpty())
        {
            h.curveData.relaHairs = relas; GenerateCircle();
        }

        OnClickHair();
    }
    public int circleCount = 15;
    public float angle;
    public Transform pivot;
    public float radius = 0.1f;
    public AnimationCurve circleLengthCurve;//时间范围0~1，中间（0.5）为正前方头发长度。0左1右
    [ShowButton]
    void DuplicateHair()
    {
        var h = hairCurr;
        if (h!=null)
        {
            var n = h.Copy();
            hairs.Add(n);
        }
    }
    [ShowButton]
    void SnapPoseKey0ToYAxis()
    {
        foreach (var h in hairs)
        {
            var k = h.curveData.pose.keys[0];
            k.vector = k.vector.SetXZ(pivot.position);
            h.curveData.SnapBonesToCurve();
        }
    }
    [ShowButton]
    void MatchMirrorBySizeAndPose()
    {
        foreach (var lh in hairs)
        {
            if (lh.curveData.pair != null) continue;
            var l = lh.genData;
            foreach (var rh in hairs)
            {
                if (lh == rh) continue;
                if (rh.curveData.pair != null) continue;
                var r = rh.genData;
                if (
                    l.width.Approx(r.width) &&
                    l.length.Approx(r.length) &&
                    l.thickness.Approx(r.thickness) &&
                    l.curveWidth.Equals(r.curveWidth) &&
                    l.curveThickness.Equals(r.curveThickness) &&
                    l.curveBoneLength.Equals(r.curveBoneLength) &&
                    l.curveCrsSecBack.Equals(r.curveCrsSecBack) &&
                    l.curveCrsSecFront.Equals(r.curveCrsSecFront) &&
                    lh.curveData.pose.IsMirror(rh.curveData.pose) &&
                    true)
                {
                    rh.name = lh.name + ".r";
                    lh.name += ".l";
                    lh.curveData.pair = rh;
                    rh.curveData.pair = lh;
                }
            }
        }
    }
    [ShowButton]
    void ClearSlope()
    {
        foreach (var hair in hairs)
        {
            hair.curveData.pose.ClearSlope();
            hair.curveData.SnapBonesToCurve();
        }
    }
    //[ShowButton]
    //void Extrude() // 曲线末尾挤出一个顶点
    //{

    //}
    [ShowButton("细分曲线")]
    void SubdividePoseCurve()
    {
        var h = hairCurr;
        if (h == null) return;
        h.curveData.pose.Subdivide();
    }
    [ShowButton]
    void GenerateCircle()
    {
        var h = hairCurr;
        if (h == null) return;
        var hs = h.curveData.relaHairs;
        if (hs.NotEmpty()) // 有则先清除关联的头发
        {
            DeleteHair(hs);
        }

        PoseScaleX0();// X轴 Scale0
        h.curveData.relaHairs = new List<Hair>();
        if (circleCount.IsEven()) circleCount++; // 偶数变为奇数
        var total = (circleCount + 1);// 加上主发束（一共是偶数）
        angle = 360f / total;
        for (int i = 0; i < circleCount; i++)
        {
            var c = h.Copy().GetComponent<Hair>();
            c.gameObject.name += ".c" + i.ToString();
            c.curveData.relaHairs.Clear();
            c.curveData.circleAngle = angle * (i + 1);

            h.curveData.relaHairs.Add(c);
            hairs.Add(c);
        }
        var origin = h.genData.length;
        int _i = 1;
        int idx;
        float t;
        int half = total / 2;
        var nList = new List<Hair>();
        foreach (var rl in h.curveData.relaHairs)
        {
            if (_i >= half)
                idx = _i - half;
            else
                idx = _i + half;
            t = (float)idx / total;
            _i++;
            rl.genData.length = circleLengthCurve.Evaluate(t) * origin;
            nList.Add(ResetGenData(rl));
        }
        h.curveData.relaHairs = nList;
        hairCurr = h;
        OnClickHair();
    }
    [ShowButton]
    void PoseScaleX0()
    {
        // 用一个trans控制发旋轴心的位置和旋转
        hairCurr.curveData.pose.Scale(new Vector3(0, 1, 1));
    }
    // 鼠标左键弹起时根据轨迹创建一条/多条头发
    void GenerateHair()
    {
        if (append) { Append(); return; }

        float length;
        if (!GetMousePos(out length)) return;

        length *= lengthProjFactor;
        var hair = AddHair(newHairName, length);
        Selector.current = hair.transform;

        Vector3[] ps = new Vector3[4];
        ps[0] = posList[0];
        ps[1] = posList[Mathf.RoundToInt((posList.Count - 1) * 0.33333f)];
        ps[2] = posList[Mathf.RoundToInt((posList.Count - 1) * 0.66667f)];
        ps[3] = posList[posList.Count - 1];
        var cd = hair.curveData;
        cd.curve = new Curve3(ps);

        if (mirror)
        {
            var hairMir = hair.Copy();
            hairMir.name += ".r";
            hair.name += ".l";
            hairs.Add(hairMir.GetComponent<Hair>());
        }

        cd.SnapBonesToCurve();

        TwistToFaceCam(cd.bones.First(), cd.curve[0]);
        TwistToFaceCam(cd.bones.Last(), cd.curve[1]);

        cd.SnapBonesToCurve(); // sync hairMir
        OnClickHair();
    }
    void TwistToFaceCam(Transform bone, Key3 k)
    {
        /// twist to face camera
        var to = Camera.main.transform.position - bone.position;
        to = to.normalized;

        var from = bone.forward;
        var axis = bone.up;
        var angle = Vector3.SignedAngle(from, to, axis);
        k.slope = angle;
    }
}
